﻿
module Octopus.OctopusLib.Utility

open System.Management


//
// ------------ WMI
//

let private getCustomImpersonatedNotExpcetionSafe_WmiObjects (username:string) (password:string) (path:string) (query:string) =
  let scope = new ManagementScope(path, null)
  if username <> null then
    scope.Options.Impersonation <- ImpersonationLevel.Impersonate
    scope.Options.Username <- username
    scope.Options.Password <- password
  let objQuery = new ObjectQuery(query)
  use searcher = new ManagementObjectSearcher(scope, objQuery)
  let coll = searcher.Get()
  let l = new System.Collections.Generic.List<ManagementObject>()
  for el in coll do l.Add(el :?> ManagementObject)
  l.ToArray()


let getCustom_WmiObjects_auth path query user pass =
  getCustomImpersonatedNotExpcetionSafe_WmiObjects user pass path query

let getCustom_WmiObject_auth path query user pass =
  let o = getCustom_WmiObjects_auth path query user pass
  if o.Length = 0 then null
  else o.[0]
  

let get_cimv2_WmiObjects_auth server query user pass =
  let path = "\\\\" + server + "\\root\\cimv2"
  getCustom_WmiObjects_auth path query user pass

let get_cimv2_WmiObject_auth server query user pass =
  let o = get_cimv2_WmiObjects_auth server query user pass
  if o.Length = 0 then null
  else o.[0]

  
//
//--------------- Octopus server - remote function invocation
//

let private octopusServer = "localhost"

let execute_remote_Octopus_function (functionInfo:string array) =
  let client = new System.Net.Sockets.TcpClient(octopusServer, 17400)
  try
    use stream = client.GetStream()
    use sw = new System.IO.StreamWriter(stream)
    use sr = new System.IO.StreamReader(stream)
    functionInfo |> Array.iter (fun x -> sw.WriteLine(x)) 
    sw.Flush()
    let result = System.Boolean.Parse(sr.ReadLine())
    if not(result) then failwith (sr.ReadLine())
    else ()
  finally
    client.Close()

let execute_remote_Octopus_function_withReturn (functionInfo:string array) =
  let client = new System.Net.Sockets.TcpClient(octopusServer, 17400)
  try
    use stream = client.GetStream()
    use sw = new System.IO.StreamWriter(stream)
    use sr = new System.IO.StreamReader(stream)
    functionInfo |> Array.iter (fun x -> sw.WriteLine(x)) 
    sw.Flush()
    let result = System.Boolean.Parse(sr.ReadLine())  
    if not(result) then failwith (sr.ReadLine())
    else sr.ReadLine()
  finally
    client.Close()


let execute_remote_Octopus_function_withArrayReturn (functionInfo:string array) =
  let client = new System.Net.Sockets.TcpClient(octopusServer, 17400)
  try
    use stream = client.GetStream()
    use sw = new System.IO.StreamWriter(stream)
    use sr = new System.IO.StreamReader(stream)
    functionInfo |> Array.iter (fun x -> sw.WriteLine(x)) 
    sw.Flush()
    let result = System.Boolean.Parse(sr.ReadLine())  
    if not(result) then failwith (sr.ReadLine())
    else
      let arraySize = System.Int32.Parse(sr.ReadLine())
      [| for i = 1 to arraySize do yield sr.ReadLine() |]
  finally
    client.Close()


//
// --------------- HyperF.VirtualMachine.Note parsing
//

let getParamNote (note:string) (param:string) =
  if note.Trim() = "" then null
  else if not(note.Contains("=")) then null
  else
    let split = note.Split([|';'|]) |> Array.map (fun x -> let s = x.Split([|'='|],2) in (s.[0].Trim(),s.[1].Trim()))
    try let p = split |> Array.find (fun (x,y) -> x = param)
        snd p
    with _ -> null
  

let removeParamNote (note:string) (param:string) =
  if note.Trim() = "" then ""
  else if not(note.Contains("=")) then note
  else
    let split = note.Split([|';'|]) |> Array.map (fun x -> let s = x.Split([|'='|],2) in (s.[0].Trim(),s.[1].Trim()))
    let tmp = split |> Array.filter (fun (x,y) -> x <> param)
    tmp |> Array.map (fun (x,y) -> sprintf "%s=%s" x y) |> String.concat "; "


let setParamNote (note:string) (param:string) (value:string) =
  if note.Trim() <> "" && not(note.Contains("=")) then failwith "Invalid notes format"
  let tmp = removeParamNote note param
  if tmp = "" then sprintf "%s=%s" param value
  else sprintf "%s; %s=%s" tmp param value


//---------------------------

module internal ObjSerializer =
  let serialize (obj:obj) =
    let formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
    use stream = new System.IO.MemoryStream()
    formatter.Serialize(stream, obj)
    stream.Seek(0L, System.IO.SeekOrigin.Begin) |> ignore
    let data = Array.zeroCreate<byte> (int stream.Length)
    stream.Read(data, 0, (int stream.Length)) |> ignore
    System.Convert.ToBase64String(data)

  let deserialize str =
    let data = System.Convert.FromBase64String(str)
    use stream = new System.IO.MemoryStream()
    stream.Write(data, 0, data.Length) |> ignore
    stream.Seek(0L, System.IO.SeekOrigin.Begin) |> ignore
    let formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
    formatter.Deserialize(stream)

//---------------------------
